package com.yuandian.customer.perception.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuandian.api.customer_perception.po.BusinessPerformanceParams;
import com.yuandian.api.customer_perception.po.SystemDomainInfo;
import com.yuandian.api.customer_perception.vo.*;
import com.yuandian.api.management.entity.ConfMenuMapping;
import com.yuandian.api.management.entity.ConfPageLabelMapping;
import com.yuandian.api.management.feign.RemoteButtonMappingService;
import com.yuandian.api.management.feign.RemoteMenuMappingService;
import com.yuandian.api.management.feign.RemotePageLabelMappingService;
import com.yuandian.api.management.feign.RemoteSystemService;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.bpm.common.data.resolver.ParamResolver;
import com.yuandian.constant.ConfigKey;
import com.yuandian.customer.perception.mapper.BusinessPerformanceMapper;
import com.yuandian.customer.perception.service.IBusinessPerformanceService;
import com.yuandian.enums.TableNameEnum;
import com.yuandian.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 说明：业务性能指标service实现
 *
 * @Author yanjun
 * @Date 2021/12/20 10:26
 */
@Slf4j
@Service
public class BusinessPerformanceServiceImpl implements IBusinessPerformanceService {

	@Autowired
	private BusinessPerformanceMapper businessPerformanceMapper;
	@Autowired
	private RemotePageLabelMappingService pageLabelMappingService;
	@Autowired
	private RemoteButtonMappingService buttonMappingService;
	@Autowired
	private RemoteMenuMappingService menuMappingService;


	/**
	 * 导出样式
	 */
	private Map<String, CellStyle> cellStyleMap;

	/**
	 * 预算域模板数据缓存  menuName:urlApi:rowList
	 */
	private LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> budgetTemplateMap;

	/**
	 * 执行域模板数据缓存  menuName:urlApi:rowList
	 */
	private LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> implementTemplateMap;

	/**
	 * 系统所属域映射
	 */
	private Map<Integer, SystemDomainInfo> systemDomainInfoMap;

	/**
	 * 菜单映射
	 */
	private Map<String, BusiPerforMenuMapping> menuMappingMap;

	/**
	 * 页签映射
	 */
	private Map<String, PageLabelMapping> pageLabelMappingMap;

	/**
	 * 按钮映射
	 */
	private Map<String, ButtonMapping> buttonMappingMap;


	/**
	 * 按导出模板生成排序序列
	 */
	@PostConstruct
	public void init() {
		boolean isLinux = System.getProperty("os.name").toLowerCase().contains("linux");

		budgetTemplateMap = new LinkedHashMap<>();
		implementTemplateMap = new LinkedHashMap<>();

		String webappRoot = null;
		if (isLinux) {
			webappRoot = this.getClass().getResource("/").getPath() + "conf/";
		} else {
			webappRoot = this.getClass().getResource("/").getPath().replaceAll("WEB-INF/classes/", "");
		}
		if (StringUtils.isEmpty(webappRoot)) {
			return;
		}
		String businessPerformancePath = null;
		FileInputStream fis = null;
		Workbook wb = null;

		try {
			businessPerformancePath = URLDecoder.decode(webappRoot, "utf-8") + "template/gdct_performance.xlsx";
			fis = new FileInputStream(businessPerformancePath);
			wb = new XSSFWorkbook(fis);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			log.error("业务性能指标模板不存在");
			return;
		} catch (IOException e) {
			e.printStackTrace();
		}

		// 预算域sheet
		Sheet budgetSheet = wb.getSheetAt(0);
		// 执行域sheet
		Sheet implementSheet = wb.getSheetAt(1);

		int budgetRowCount = budgetSheet.getLastRowNum();
		int implementRowCount = implementSheet.getLastRowNum();
		String frontMenuName1 = null;
		for (int i = 2; i < budgetRowCount; i++) {
			Row row = budgetSheet.getRow(i);
			String menuName = row.getCell(4).getStringCellValue();
			String urlApi = row.getCell(6).getStringCellValue();
			if (StringUtils.isNotEmpty(menuName)) {
				frontMenuName1 = menuName;
			} else {
				menuName = frontMenuName1;
			}
			LinkedHashMap<String, List<BusinessPerformanceTransVo>> map = budgetTemplateMap
					.computeIfAbsent(menuName, k -> new LinkedHashMap<>());
			map.computeIfAbsent(urlApi, k -> new ArrayList<>());
		}
		String frontMenuName2 = null;
		for (int i = 2; i < implementRowCount; i++) {
			Row row = implementSheet.getRow(i);
			String menuName = row.getCell(5).getStringCellValue();
			String urlApi = row.getCell(7).getStringCellValue();
			if (StringUtils.isNotEmpty(menuName)) {
				frontMenuName2 = menuName;
			} else {
				menuName = frontMenuName2;
			}
			LinkedHashMap<String, List<BusinessPerformanceTransVo>> map = implementTemplateMap
					.computeIfAbsent(menuName, k -> new LinkedHashMap<>());
			map.computeIfAbsent(urlApi, k -> new ArrayList<>());
		}
		log.info("业务性能指标模板加载完成，path: {}", businessPerformancePath);
	}

	/**
	 * 查询业务性能指标列表过滤项
	 *
	 * @param params 业务性能指标查询参数对象
	 * @return 通用返回对象
	 */
	@Override
	public R queryBusinessPerformanceOptions(BusinessPerformanceParams params) {
		Map<String, List<SelectPojo>> res = new HashMap<>();
		List<String> filterFieldList = params.getFilterFieldList();
		for (String field : filterFieldList) {
			params.setFilterField(field);
			List<SelectPojo> options = businessPerformanceMapper.queryBusinessPerformanceOptions(params);
			res.put(field, options);
		}
		return R.ok(res);
	}

	/**
	 * 查询业务性能指标列表
	 *
	 * @param params 业务性能指标查询参数对象
	 * @return 通用返回对象
	 */
	@Override
	public R queryBusinessPerformanceList(BusinessPerformanceParams params) {
		// 1、通用查询处理
		Map<String, List<SelectPojo>> filterMap = null;
		filterMap = new HashMap<>();

		// 组装数据发生在此处，首先要用要将list转成map，
		// key用menuId、pageLabelId、pageSize、operatorId通过@拼接，相同的就进行合并
		// 一号维度：menuId、pageLabelId、pageSize、operatorId ；二号维度：menuId、pageLabelId、pageSize、operatorId、buttonId
		// 用一号维度的数据区回填二号维度的数据也就是页签的速度


		Map<String, Object> map = commonQuery(params, filterMap);
		int activeOperatorCount = BeanUtils.cast(map.get("activeOperatorCount"));
		int collectDataCount = BeanUtils.cast(map.get("collectDataCount"));

		List<BusinessPerformanceTransVo> voList = new ArrayList<>();
		// 加工数据
		voList = dealData(params, filterMap, null);
		voList = filterData(params, filterMap, voList);

		//

		// 3、返回结果集
		int total = voList.size();
		long pageNum = params.getPageNum();
		long pageSize = params.getPageSize();
		int start = Long.valueOf((pageNum - 1) * pageSize).intValue();
		int end = Long.valueOf(pageNum * pageSize).intValue();
		if (start > total) {
			start = 0;
		}
		if (end > total) {
			end = total;
		}
		Map<String, Object> res = new HashMap<>();
		res.put("pageDataInfo", new PageDataInfo(total, voList.subList(start, end)));
		res.put("filterMap", filterMap);
		res.put("activeOperatorCount", activeOperatorCount);
		res.put("collectDataCount", collectDataCount);
		return R.ok(res);
	}

	/**
	 * 下载业务性能指标列表
	 *
	 * @param params   业务性能指标查询参数对象
	 * @param response 响应上下文
	 */
	@Override
	public void exportBusinessPerformanceList(BusinessPerformanceParams params, HttpServletResponse response) {
		// 1、通用查询处理
		params.setPageNum(0);
		Map<String, Object> map = commonQuery(params, null);
//        LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> budgetDataMap = BeanUtils.cast(map.get("budget"));
//        LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> implementDataMap = BeanUtils.cast(map.get("implement"));
		List<BusinessPerformanceTransVo> budgetss = dealData(params, null, "budget");
		List<BusinessPerformanceTransVo> implementss = dealData(params, null, "implement");
		List<BusinessPerformanceTransVo> checkss = dealData(params, null, "check");
		List<BusinessPerformanceTransVo> fanruanss = dealData(params, null, "fanruan");

		List<BusinessPerformanceTransVo> budgetPaperss = new ArrayList<>();
		int selectedSdi = BeanUtils.cast(map.get("selectedSdi"));

		// 2、组装导出数据
		List<List<String>> budgetList = new ArrayList<>();
		List<List<String>> implementList = new ArrayList<>();
		List<List<String>> checkList = new ArrayList<>();
		//预算域报表速度
		List<List<String>> budgetPaperList = new ArrayList<>();
		//执行域报表速度
		List<List<String>> implementPaperList = new ArrayList<>();

		AtomicInteger budgetCount = new AtomicInteger(1);
		AtomicInteger implementCount = new AtomicInteger(1);
		AtomicInteger checkCount = new AtomicInteger(1);
		AtomicInteger budgetPaperCount = new AtomicInteger(1);
		AtomicInteger implementPaperCount = new AtomicInteger(1);


		ConfPageLabelMapping confPageLabelMapping = pageLabelMappingService.getFixPageLabelMapping("2", "0000").getData();
		PageLabelMapping mapping = new PageLabelMapping();
		BeanUtil.copyProperties(confPageLabelMapping, mapping);
		//预算域报表速度处理
		budgetss.forEach(vo -> {
			if ("/boss/report/html/reportWithRight.html".equals(vo.getUrlApi())) {
				budgetPaperss.add(vo);
			}
		});
		updateData(budgetPaperss, budgetPaperList, budgetPaperCount, mapping, 1, null);

		updateData(budgetss, budgetList, budgetCount, mapping, 1, null);


		updateData(implementss, implementList, implementCount, mapping, 2, null);


		updateData(checkss, checkList, checkCount, mapping, 1, "hesuan");

		updateData(fanruanss, implementPaperList, implementPaperCount, mapping, 1, null);


		// 3、生成excel
		HSSFWorkbook wb = new HSSFWorkbook();
		createStyle(wb);
		if (selectedSdi == 0 || selectedSdi == 1) {
			if (budgetList.size() > 0) {
				createBudgetSheet(wb, budgetList, "预算域页面功能");
			}

		}
		if (selectedSdi == 0 || selectedSdi == 2) {
			if (implementList.size() > 0) {
				createImplementSheet(wb, implementList);
			}

		}
		if (selectedSdi == 0 || selectedSdi == 3) {
			if (checkList.size() > 0) {
				createBudgetSheet(wb, checkList, "核算域页面功能");
			}

		}
		if (selectedSdi == 0 || selectedSdi == 1) {
			if (budgetPaperList.size() > 0) {
				createBudgetSheet(wb, budgetPaperList, "预算域报表");
			}

		}
		if (selectedSdi == 0 || selectedSdi == 2) {
			if (implementPaperList.size() > 0) {
				createBudgetSheet(wb, implementPaperList, "执行域报表");
			}

		}

		// 4、写回浏览器
		String fileName = "财厅业务功能性能数据列表" + YDateUtil.yyyyMMddHHmmss(params.getStartTime())
				+ "~" + DateTool.yyyyMMddHHmmss(params.getEndTime());
		response.reset();
		response.setContentType("application/msexcel; charset=utf-8");
		try {
			if ("firefox".equals(params.getBrowser())) {
				fileName = "=?UTF-8?B?" + new String(Base64.getEncoder().encode(fileName.getBytes("utf-8"))) + "?=";
			} else {
				fileName = URLEncoder.encode(fileName, "utf-8");
			}
			response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".xls");
			wb.write(response.getOutputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}


	private void updateData(List<BusinessPerformanceTransVo> budgetss, List<List<String>> budgetList, AtomicInteger budgetCount, PageLabelMapping mapping, Integer type, String typeStr) {
		for (int i = 0; i < budgetss.size(); i++) {
			BusinessPerformanceTransVo l = budgetss.get(i);
			//如果字段为空，则替换成横杠
			if (StringUtils.isBlank(l.getMenuId())) l.setMenuId("-");
			if (StringUtils.isBlank(l.getMenuName())) l.setMenuName("-");
			if (StringUtils.isBlank(l.getParentMenuName())) l.setParentMenuName("-");
			if (StringUtils.isBlank(l.getUrlApi())) l.setUrlApi("-");
			if ("hesuan".equals(typeStr)) {
				if (StringUtils.isBlank(l.getPageLabelName())) l.setPageLabelName("全部");
				if (StringUtils.isBlank(l.getPageSizeStr())) l.setPageSizeStr("20");
				if (StringUtils.isBlank(l.getPageSizeZone())) l.setPageSizeZone("小于等于50笔");
			} else {
				if (mapping != null) {
					if (StringUtils.isBlank(l.getPageLabelName())) l.setPageLabelName(mapping.getPageLabelName());
				}
			}
			if (StringUtils.isBlank(l.getPageSizeStr())) l.setPageSizeStr("-");
			if (StringUtils.isBlank(l.getPageSizeZone())) l.setPageSizeZone("-");
			if (StringUtils.isBlank(l.getButtonName())) l.setButtonName("-");
			if (StringUtils.isBlank(l.getBusinessModuleName())) l.setBusinessModuleName("-");
			if (StringUtils.isBlank(l.getOperatorName())) l.setOperatorName("-");
			if (StringUtils.isBlank(l.getButtonSpeed())) l.setButtonSpeed("-");
			if (StringUtils.isBlank(l.getButtonUrlApi())) l.setButtonUrlApi("-");
			if (StringUtils.isBlank(l.getButtonSpeedZone())) l.setButtonSpeedZone("-");
			if (StringUtils.isBlank(l.getButtonSize())) l.setButtonSize("-");

			if (type == 1) {
				budgetList.add(Arrays.asList(String.valueOf(budgetCount.getAndIncrement()), l.getDomainName(), l.getBusinessModuleName(),
						l.getMenuId(), l.getMenuName(), l.getUrlApi(), l.getUrlApi(), l.getPageLabelName(),
						l.getPageSizeStr(), l.getSpeed(), l.getSpeedZone(), l.getPageSizeZone(),
						l.getButtonName(), l.getButtonSize(), l.getButtonSpeed(), l.getButtonSpeedZone(), l.getButtonUrlApi(), l.getButtonUrlApi(), l.getButtonReqCount(), l.getOperatorName()));
			} else {
				budgetList.add(Arrays.asList(String.valueOf(budgetCount.getAndIncrement()), l.getDomainName(), l.getBusinessModuleName(),
						l.getMenuId(), l.getParentMenuName(), l.getMenuName(), l.getUrlApi(), l.getUrlApi(), l.getPageLabelName(),
						l.getPageSizeStr(), l.getSpeed(), l.getSpeedZone(), l.getPageSizeZone(),
						l.getButtonName(), l.getButtonSize(), l.getButtonSpeed(), l.getButtonSpeedZone(), l.getButtonUrlApi(), l.getButtonUrlApi(), l.getButtonReqCount(), l.getOperatorName()));
			}

		}
	}

	private List<BusinessPerformanceTransVo> dealData(BusinessPerformanceParams params, Map<String, List<SelectPojo>> filterMap, String type) {
		//二号维度：menuId、pageLabelId、pageSize、operatorId，buttonId
		Map<String, Object> map = commonQuery(params, filterMap);
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> budgetDataMap = BeanUtils.cast(map.get("budget"));
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> implementDataMap = BeanUtils.cast(map.get("implement"));
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> checkDataMap = BeanUtils.cast(map.get("check"));
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> fanruanDataMap = BeanUtils.cast(map.get("fanruan"));

		//一号维度：menuId、pageLabelId、pageSize、operatorId
		Map<String, Object> map1 = commonQuery2(params, filterMap);
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> budgetDataMap1 = BeanUtils.cast(map1.get("budget"));
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> implementDataMap1 = BeanUtils.cast(map1.get("implement"));
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> checkDataMap1 = BeanUtils.cast(map1.get("check"));
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> fanruanDataMap1 = BeanUtils.cast(map1.get("fanruan"));

		// 2、组装vo数据
		List<BusinessPerformanceTransVo> voList = new ArrayList<>();
		// 2、组装vo数据
		List<BusinessPerformanceTransVo> voList1 = new ArrayList<>();
		if (type == null) {

			// 预算域结果集
			budgetDataMap.forEach((menuName, urlMap) -> {
				urlMap.forEach((urlApi, list) -> {
					voList.addAll(list);
				});
			});
			// 执行域结果集
			implementDataMap.forEach((menuName, urlMap) -> {
				urlMap.forEach((urlApi, list) -> {
					voList.addAll(list);
				});
			});
			checkDataMap.forEach((menuName, urlMap) -> {
				urlMap.forEach((urlApi, list) -> {
					voList.addAll(list);
				});
			});
			//将url和速度赋值给按钮的url和速度
			voList.forEach(vo -> {
				if (StringUtils.isNotBlank(vo.getButtonName())) {
					vo.setButtonSpeed(vo.getSpeed());
					vo.setButtonUrlApi(vo.getUrlApi());
					vo.setButtonSpeedZone(vo.getSpeedZone());
					vo.setButtonReqCount(vo.getReqCount());
					vo.setButtonPageSizeStr(vo.getPageSizeStr());
					vo.setButtonPageLabelId(vo.getPageLabelId());
					vo.setSpeed(null);
					vo.setUrlApi(null);
					vo.setSpeedZone(null);
					vo.setReqCount(null);
				}
			});


			// 预算域结果集
			budgetDataMap1.forEach((menuName, urlMap) -> {
				urlMap.forEach((urlApi, list) -> {
					voList1.addAll(list);
				});
			});
			// 执行域结果集
			implementDataMap1.forEach((menuName, urlMap) -> {
				urlMap.forEach((urlApi, list) -> {
					voList1.addAll(list);
				});
			});
			checkDataMap1.forEach((menuName, urlMap) -> {
				urlMap.forEach((urlApi, list) -> {
					voList1.addAll(list);
				});
			});
		} else if ("budget".equals(type)) {
			// 预算域结果集
			budgetDataMap.forEach((menuName, urlMap) -> {
				urlMap.forEach((urlApi, list) -> {
					voList.addAll(list);
				});
			});
			//将url和速度赋值给按钮的url和速度
			voList.forEach(vo -> {
				if (StringUtils.isNotBlank(vo.getButtonName())) {
					vo.setButtonSpeed(vo.getSpeed());
					vo.setButtonUrlApi(vo.getUrlApi());
					vo.setButtonSpeedZone(vo.getSpeedZone());
					vo.setButtonReqCount(vo.getReqCount());
					vo.setButtonPageSizeStr(vo.getPageSizeStr());
					vo.setButtonPageLabelId(vo.getPageLabelId());
					vo.setSpeed(null);
					vo.setUrlApi(null);
					vo.setSpeedZone(null);
					vo.setReqCount(null);
				}
			});

			// 预算域结果集
			budgetDataMap1.forEach((menuName, urlMap) -> {
				urlMap.forEach((urlApi, list) -> {
					voList1.addAll(list);
				});
			});
		} else if ("implement".equals(type)) {
			// 执行域结果集
			implementDataMap.forEach((menuName, urlMap) -> {
				urlMap.forEach((urlApi, list) -> {
					voList.addAll(list);
				});
			});
			//将url和速度赋值给按钮的url和速度
			voList.forEach(vo -> {
				if (StringUtils.isNotBlank(vo.getButtonName())) {
					vo.setButtonSpeed(vo.getSpeed());
					vo.setButtonUrlApi(vo.getUrlApi());
					vo.setButtonSpeedZone(vo.getSpeedZone());
					vo.setButtonReqCount(vo.getReqCount());
					vo.setButtonPageSizeStr(vo.getPageSizeStr());
					vo.setButtonPageLabelId(vo.getPageLabelId());
					vo.setSpeed(null);
					vo.setUrlApi(null);
					vo.setSpeedZone(null);
					vo.setReqCount(null);
				}
			});

			// 执行域结果集
			implementDataMap1.forEach((menuName, urlMap) -> {
				urlMap.forEach((urlApi, list) -> {
					voList1.addAll(list);
				});
			});
		} else if ("check".equals(type)) {
			// 核算域结果集
			checkDataMap.forEach((menuName, urlMap) -> {
				urlMap.forEach((urlApi, list) -> {
					voList.addAll(list);
				});
			});
			//将url和速度赋值给按钮的url和速度
			voList.forEach(vo -> {
				if (StringUtils.isNotBlank(vo.getButtonName())) {
					vo.setButtonSpeed(vo.getSpeed());
					vo.setButtonUrlApi(vo.getUrlApi());
					vo.setButtonSpeedZone(vo.getSpeedZone());
					vo.setButtonReqCount(vo.getReqCount());
					vo.setButtonPageSizeStr(vo.getPageSizeStr());
					vo.setButtonPageLabelId(vo.getPageLabelId());
					vo.setSpeed(null);
					vo.setUrlApi(null);
					vo.setSpeedZone(null);
					vo.setReqCount(null);
				}
			});

			// 执行域结果集
			checkDataMap1.forEach((menuName, urlMap) -> {
				urlMap.forEach((urlApi, list) -> {
					voList1.addAll(list);
				});
			});
		} else if ("fanruan".equals(type)) {
			// 核算域结果集
			fanruanDataMap.forEach((menuName, urlMap) -> {
				urlMap.forEach((urlApi, list) -> {
					voList.addAll(list);
				});
			});
			//将url和速度赋值给按钮的url和速度
			voList.forEach(vo -> {
				if (StringUtils.isNotBlank(vo.getButtonName())) {
					vo.setButtonSpeed(vo.getSpeed());
					vo.setButtonUrlApi(vo.getUrlApi());
					vo.setButtonSpeedZone(vo.getSpeedZone());
					vo.setButtonReqCount(vo.getReqCount());
					vo.setButtonPageSizeStr(vo.getPageSizeStr());
					vo.setButtonPageLabelId(vo.getPageLabelId());
					vo.setSpeed(null);
					vo.setUrlApi(null);
					vo.setSpeedZone(null);
					vo.setReqCount(null);
				}
			});

			// 执行域结果集
			fanruanDataMap1.forEach((menuName, urlMap) -> {
				urlMap.forEach((urlApi, list) -> {
					voList1.addAll(list);
				});
			});
		}

		List<BusinessPerformanceTransVo> list = aggData(voList1, voList);

		//遍历数据，组装新增的过滤项
		return list;
	}

	/**
	 * 归并数据，
	 * // 组装数据发生在此处，首先要用要将list转成map，
	 * // key用menuId、pageLabelId、pageSize、operatorId通过@拼接，相同的就进行合并
	 * // 一号维度：menuId、pageLabelId、pageSize、operatorId ；二号维度：menuId、pageLabelId、pageSize、operatorId、buttonId
	 * // 用一号维度的数据区回填二号维度的数据也就是页签的速度，能回填得上的数据标记为1，得到临时list
	 * // 再遍历临时list，如果回填得上的则不处理这条数据
	 * // 如果回填不上，则判断buttonId是否有值，有值的话，速度和url属于按钮，否则属于页签
	 *
	 * @param voList1 1号维度数据
	 * @param voList  2号维度数据
	 * @return
	 */
	private List<BusinessPerformanceTransVo> aggData(List<BusinessPerformanceTransVo> voList1, List<BusinessPerformanceTransVo> voList) {
		//1号维度map
		HashMap<String, BusinessPerformanceTransVo> voMap1 = new HashMap<>();
		//1号维度重复的数据
		List<BusinessPerformanceTransVo> list1 = new ArrayList<>();
		//2号维度map
		HashMap<String, BusinessPerformanceTransVo> voMap = new HashMap<>();
		//2号维度重复的数据
		List<BusinessPerformanceTransVo> list2 = new ArrayList<>();
		//将list转成map
		voList1.forEach(businessPerformanceTransVo -> {
			String key = businessPerformanceTransVo.getMenuId() + "@"
					+ businessPerformanceTransVo.getPageLabelId() + "@"
					+ businessPerformanceTransVo.getOperatorId();
			if (voMap1.containsKey(key)) {
				list1.add(businessPerformanceTransVo);
			} else {
				voMap1.put(key, businessPerformanceTransVo);
			}

		});

		voList.forEach(businessPerformanceTransVo -> {
			String key = businessPerformanceTransVo.getMenuId() + "@"
					+ businessPerformanceTransVo.getPageLabelId() + "@"
					+ businessPerformanceTransVo.getOperatorId();
			if (voMap.containsKey(key)) {
				if (StringUtils.isNotBlank(businessPerformanceTransVo.getButtonName())) {
					list2.add(businessPerformanceTransVo);
				}
			} else {
				voMap.put(key, businessPerformanceTransVo);
			}
		});


		//用1号维度的数据去回填二号维度的数据
		voMap.forEach((s, vo) -> {
			if (voMap1.get(s) != null) {
				vo.setSpeed(voMap1.get(s).getSpeed());
				vo.setUrlApi(voMap1.get(s).getUrlApi());
				vo.setSpeedZone(voMap1.get(s).getSpeedZone());
				vo.setReqCount(voMap1.get(s).getReqCount());
				vo.setPageSizeZone(voMap1.get(s).getPageSizeZone());
				vo.setPageSizeStr(voMap1.get(s).getPageSizeStr());
			}
		});

		List<BusinessPerformanceTransVo> resultList = new ArrayList<>();
		list2.forEach(vo -> {
			String key = vo.getMenuId() + "@"
					+ vo.getPageLabelId() + "@"
					+ vo.getOperatorId();
			if (voMap.get(key) != null && StringUtils.isBlank(voMap.get(key).getButtonName())) {
				vo.setSpeed(voMap.get(key).getSpeed());
				vo.setUrlApi(voMap.get(key).getUrlApi());
				vo.setSpeedZone(voMap.get(key).getSpeedZone());
				vo.setReqCount(voMap.get(key).getReqCount());
				vo.setPageSizeZone(voMap.get(key).getPageSizeZone());
				vo.setPageSizeStr(voMap.get(key).getPageSizeStr());
				voMap.remove(key);
			}
			resultList.add(vo);
		});
		list1.forEach(vo -> {
			resultList.add(vo);
		});
		voMap.forEach((s, vo) -> {
			resultList.add(vo);
		});

		// 判断页签的速度是不是回填上去的，如果是，则不删除，
		// 如果不是，则判断按钮id是否为空，如果不为空，则删除页签id
//        resultList.forEach(vo -> {
//            if ("1".equals(vo.getHavePageSpeed())) {
//                if (StringUtils.isBlank(vo.getButtonId())) {
//                    vo.setButtonUrlApi(null);
//                    vo.setButtonSpeed(null);
//                }
//            } else {
//                if (StringUtils.isBlank(vo.getButtonId())) {
//                    vo.setButtonUrlApi(null);
//                    vo.setButtonSpeed(null);
//                }
//            }
//        });

		//bug6375、当ButtonReqCount为空时，回填RequestCount，如果还为空，则不回填
		resultList.forEach(vo -> {
			if (StringUtils.isBlank(vo.getButtonReqCount()) && StringUtils.isNotBlank(vo.getReqCount())) {
				vo.setButtonReqCount(vo.getReqCount());
				vo.setIsBackFill("1");
			}
		});
		return resultList;
	}

	/**
	 * 通用查询处理
	 *
	 * @param params 业务性能指标查询参数对象
	 * @return map
	 */
	private Map<String, Object> commonQuery(
			BusinessPerformanceParams params, Map<String, List<SelectPojo>> filterMap) {
		Map<String, Object> map = new HashMap<>();

		// 1、设置分页，因为要按模板导出，这里查所有数据，后续手动分页
		Page<BusinessPerformanceVo> page = null;
        /*if (params.getPageNum() > 0) {
            page = new Page<>(params.getPageNum(), params.getPageSize());
        }*/

		// 2、查询业务性能指标列表数据
		List<BusinessPerformanceVo> dataList = queryPerformanceList(params);

		// 3、查询系统所属域信息
		List<SystemDomainInfo> systemDomainList = new ArrayList<>();// todo businessPerformanceMapper.querySystemDomainList();
		systemDomainInfoMap = systemDomainList
				.stream()
				.collect(Collectors.toMap(SystemDomainInfo::getSystemId, t -> t, (k1, k2) -> k1));
		// 判断所选系统所属域是全部还是具体哪个域
		SystemDomainInfo sdi = systemDomainInfoMap.get(params.getSystemId());
		if (sdi == null) {
			// 全部
			map.put("selectedSdi", 0);
		} else if ("budget".equals(sdi.getSystemDomainCode())) {
			// 预算域
			map.put("selectedSdi", 1);
		} else if ("implement".equals(sdi.getSystemDomainCode())) {
			// 执行域
			map.put("selectedSdi", 2);
		} else if ("check".equals(sdi.getSystemDomainCode())) {
			// 执行域
			map.put("selectedSdi", 3);
		} else if ("fanruan".equals(sdi.getSystemDomainCode())) {
			// 执行域
			map.put("selectedSdi", 4);
		}

		// 4、查询菜单映射
		List<ConfMenuMapping> confMenuMappings = menuMappingService.getAllConfMenuMapping().getData();
		List<BusiPerforMenuMapping> menuMappingList = BeanUtil.copyToList(confMenuMappings, BusiPerforMenuMapping.class);
		menuMappingMap = menuMappingList
				.stream()
				.collect(Collectors.toMap(BusiPerforMenuMapping::getMenuId, t -> t, (k1, k2) -> k1));

		// 5、复制模板序列
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> budgetDataMap = new LinkedHashMap<>();
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> implementDataMap = new LinkedHashMap<>();
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> checkDataMap = new LinkedHashMap<>();
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> fanruanDataMap = new LinkedHashMap<>();


		// 6、计算、转换数据
		Integer totalReqCount = 0;
		Integer budgetSeq = 0;
		Integer implementSeq = 0;
		Integer checkSeq = 0;
		Integer fanruanSeq = 0;


		// 去重统计用户数
		Set<String> operatorIdSet = new HashSet<>();
		for (int i = 0; i < dataList.size(); i++) {
			BusinessPerformanceVo bp = dataList.get(i);
			SystemDomainInfo systemDomainInfo = systemDomainInfoMap
					.computeIfAbsent(bp.getSystemId(), k -> new SystemDomainInfo());
			BusiPerforMenuMapping menuMapping = menuMappingMap
					.computeIfAbsent(bp.getMenuId(), k -> new BusiPerforMenuMapping());

			// 分页大小
			Integer pageSize = null;
			String pageSizeStr = bp.getPageSize();
			if (StringUtils.isNotEmpty(pageSizeStr) && !"全部".equals(pageSizeStr)) {
				pageSize = Integer.valueOf(pageSizeStr);
			}
			// 请求笔数
			Integer reqCount = bp.getReqCount();
			// 总处理时长
			Long totalDealTime = bp.getTotalDealTime();
			// 计算速度
			double v = new BigDecimal((totalDealTime / (float) reqCount) / 1000000)
					.setScale(3, BigDecimal.ROUND_HALF_UP)
					.doubleValue();

			// 速度区间
			String vZone = null;
			if (v >= 0 && v <= 2) {
				vZone = "小于等于2秒";
			} else if (v > 2 && v <= 5) {
				vZone = "2到5秒";
			} else {
				vZone = "大于5秒";
			}
			// 笔数区间
			String pageSizeZone = null;
			if (pageSize != null) {
				if (pageSize >= 0 && pageSize <= 50) {
					pageSizeZone = "小于等于50笔";
				} else if (pageSize > 50 && pageSize <= 1000) {
					pageSizeZone = "50到1000笔";
				} else if (pageSize > 1000 && pageSize < 10000) {
					pageSizeZone = "1000到10000笔";
				} else {
					pageSizeZone = "大于10000笔";
				}
			}

			// 如果是过滤搜索，判断是否满足过滤条件
			List<String> filterFieldList = Arrays.asList("businessModuleName", "menuId", "menuName", "urlApi", "pageLabelName",
					"pageSizeStr", "speed", "speedZone", "pageSizeZone", "buttonName", "buttonSize", "operatorName");
			List<String> filterValList = Arrays.asList(menuMapping.getBusinessModuleName(), bp.getMenuId(),
					bp.getMenuName(), bp.getUrlApi(), bp.getPageLabelName(), pageSizeStr, String.valueOf(v),
					vZone, pageSizeZone, bp.getButtonName(), bp.getButtonSize(), bp.getOperatorName());

			BusinessPerformanceTransVo vo = null;
			String domainCode = systemDomainInfo.getSystemDomainCode();
			String domainName = systemDomainInfo.getSystemDomainName();
			if ("budget".equals(domainCode)) {
				totalReqCount = totalReqCount + changeData(budgetDataMap, bp, vo, budgetSeq, domainName, menuMapping, pageSizeStr, v, vZone, pageSizeZone, totalReqCount);
			} else if ("implement".equals(domainCode)) {
				totalReqCount = totalReqCount + changeData(implementDataMap, bp, vo, implementSeq, domainName, menuMapping, pageSizeStr, v, vZone, pageSizeZone, totalReqCount);

			} else if ("check".equals(domainCode)) {
				totalReqCount = totalReqCount + changeData(checkDataMap, bp, vo, checkSeq, domainName, menuMapping, pageSizeStr, v, vZone, pageSizeZone, totalReqCount);
			} else if ("fanruan".equals(domainCode)) {
				totalReqCount = totalReqCount + changeData(fanruanDataMap, bp, vo, fanruanSeq, domainName, menuMapping, pageSizeStr, v, vZone, pageSizeZone, totalReqCount);
			} else {
				// 非预算域、非执行域
				continue;
			}

			// 统计用户数
			operatorIdSet.add(bp.getOperatorId());

			// 组装过滤项数据
			if (filterMap == null) {
				continue;
			}
			for (int j = 0; j < filterFieldList.size(); j++) {
				String filterField = filterFieldList.get(j);
				String filterVal = filterValList.get(j) == null ? "" : filterValList.get(j);
				List<SelectPojo> selectPojoList;
				selectPojoList = filterMap.computeIfAbsent(filterField, k -> new ArrayList<>());
				if (selectPojoList.stream().noneMatch(k -> k.getKey().equals(filterVal))) {
					SelectPojo sp = new SelectPojo();
					sp.setKey(filterVal);
					sp.setValue(filterVal);
					selectPojoList.add(sp);
				}
			}
		}

		// 7、分类返回结果集
		map.put("budget", budgetDataMap);
		map.put("implement", implementDataMap);
		map.put("check", checkDataMap);
		map.put("fanruan", fanruanDataMap);
		map.put("activeOperatorCount", operatorIdSet.size());
		map.put("collectDataCount", totalReqCount);
		return map;
	}


	private Integer changeData(LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> implementDataMap,
							   BusinessPerformanceVo bp, BusinessPerformanceTransVo vo, int implementSeq, String domainName,
							   BusiPerforMenuMapping menuMapping, String pageSizeStr, double v, String vZone, String pageSizeZone,
							   Integer totalReqCount) {

		// 执行域
		// LinkedHashMap<String, List<BusinessPerformanceTransVo>> urlMap = implementDataMap.get(bp.getMenuName());
		LinkedHashMap<String, List<BusinessPerformanceTransVo>> urlMap = implementDataMap.computeIfAbsent(bp.getMenuName(), k -> new LinkedHashMap<>());
		// List<BusinessPerformanceTransVo> list = urlMap.get(bp.getUrlApi());
		List<BusinessPerformanceTransVo> list = urlMap.computeIfAbsent(bp.getUrlApi(), k -> new ArrayList<>());
		vo = new BusinessPerformanceTransVo();
		vo.setSeqNo(String.valueOf(implementSeq++));
		vo.setSystemId(bp.getSystemId());
		vo.setSystemName(bp.getSystemName());
		vo.setDomainName(domainName);
		vo.setBusinessModuleName(menuMapping.getBusinessModuleName());
		vo.setMenuId(bp.getMenuId());
		vo.setParentMenuName(menuMapping.getParentMenuName());
		vo.setMenuName(bp.getMenuName());
		vo.setUrlApi(bp.getUrlApi());
		vo.setPageLabelId(bp.getPageLabelId());
		vo.setPageLabelName(bp.getPageLabelName());
		vo.setPageSizeStr(pageSizeStr);
		vo.setSpeed(String.valueOf(v));
		vo.setSpeedZone(vZone);
		vo.setPageSizeZone(pageSizeZone);
		vo.setButtonId(bp.getButtonId());
		vo.setButtonName(bp.getButtonName());
		vo.setReqCount(bp.getReqCount().toString());
		vo.setOperatorId(bp.getOperatorId());
		vo.setOperatorName(bp.getOperatorName());
		vo.setButtonSize(bp.getButtonSize());
		list.add(vo);
		return bp.getReqCount();
	}

	/**
	 * 通用查询处理
	 *
	 * @param params 业务性能指标查询参数对象
	 * @return map
	 */
	private Map<String, Object> commonQuery2(
			BusinessPerformanceParams params, Map<String, List<SelectPojo>> filterMap) {
		Map<String, Object> map = new HashMap<>();

		// 1、设置分页，因为要按模板导出，这里查所有数据，后续手动分页
		Page<BusinessPerformanceVo> page = null;
        /*if (params.getPageNum() > 0) {
            page = new Page<>(params.getPageNum(), params.getPageSize());
        }*/

		// 2、查询业务性能指标列表数据
		List<BusinessPerformanceVo> dataList = queryPerformanceList2(params);

		// 3、查询系统所属域信息
		List<SystemDomainInfo> systemDomainList = new ArrayList<>(); // todo businessPerformanceMapper.querySystemDomainList();
		systemDomainInfoMap = systemDomainList
				.stream()
				.collect(Collectors.toMap(SystemDomainInfo::getSystemId, t -> t, (k1, k2) -> k1));
		// 判断所选系统所属域是全部还是具体哪个域
		SystemDomainInfo sdi = systemDomainInfoMap.get(params.getSystemId());
		if (sdi == null) {
			// 全部
			map.put("selectedSdi", 0);
		} else if ("budget".equals(sdi.getSystemDomainCode())) {
			// 预算域
			map.put("selectedSdi", 1);
		} else if ("implement".equals(sdi.getSystemDomainCode())) {
			// 执行域
			map.put("selectedSdi", 2);
		} else if ("check".equals(sdi.getSystemDomainCode())) {
			// 执行域
			map.put("selectedSdi", 3);
		} else if ("fanruan".equals(sdi.getSystemDomainCode())) {
			// 执行域
			map.put("selectedSdi", 4);
		}

		// 4、查询菜单映射
		List<ConfMenuMapping> confMenuMappings = menuMappingService.getAllConfMenuMapping().getData();
		List<BusiPerforMenuMapping> menuMappingList = BeanUtil.copyToList(confMenuMappings, BusiPerforMenuMapping.class);
		menuMappingMap = menuMappingList
				.stream()
				.collect(Collectors.toMap(BusiPerforMenuMapping::getMenuId, t -> t, (k1, k2) -> k1));

		// 5、复制模板序列
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> budgetDataMap = new LinkedHashMap<>();
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> implementDataMap = new LinkedHashMap<>();
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> checkDataMap = new LinkedHashMap<>();
		LinkedHashMap<String, LinkedHashMap<String, List<BusinessPerformanceTransVo>>> fanruanDataMap = new LinkedHashMap<>();

		budgetTemplateMap.forEach((menuName, urlMap) -> {
			LinkedHashMap<String, List<BusinessPerformanceTransVo>> m = budgetDataMap
					.computeIfAbsent(menuName, k -> new LinkedHashMap<>());
			urlMap.forEach((urlApi, list) -> {
				m.computeIfAbsent(urlApi, k -> new ArrayList<>());
			});
		});
		implementTemplateMap.forEach((menuName, urlMap) -> {
			LinkedHashMap<String, List<BusinessPerformanceTransVo>> m = implementDataMap
					.computeIfAbsent(menuName, k -> new LinkedHashMap<>());
			urlMap.forEach((urlApi, list) -> {
				m.computeIfAbsent(urlApi, k -> new ArrayList<>());
			});
		});

		// 6、计算、转换数据
		int totalReqCount = 0;
		int budgetSeq = 0;
		int implementSeq = 0;
		int checkSeq = 0;
		int fanruanSeq = 0;


		// 去重统计用户数
		Set<String> operatorIdSet = new HashSet<>();
		for (int i = 0; i < dataList.size(); i++) {
			BusinessPerformanceVo bp = dataList.get(i);
			SystemDomainInfo systemDomainInfo = systemDomainInfoMap
					.computeIfAbsent(bp.getSystemId(), k -> new SystemDomainInfo());
			BusiPerforMenuMapping menuMapping = menuMappingMap
					.computeIfAbsent(bp.getMenuId(), k -> new BusiPerforMenuMapping());

			// 分页大小
			Integer pageSize = null;
			String pageSizeStr = bp.getPageSize();
			if (StringUtils.isNotEmpty(pageSizeStr) && !"全部".equals(pageSizeStr)) {
				pageSize = Integer.valueOf(pageSizeStr);
			}
			// 请求笔数
			Integer reqCount = bp.getReqCount();
			// 总处理时长
			Long totalDealTime = bp.getTotalDealTime();
			// 计算速度
			double v = new BigDecimal((totalDealTime / (float) reqCount) / 1000000)
					.setScale(3, BigDecimal.ROUND_HALF_UP)
					.doubleValue();

			// 速度区间
			String vZone = null;
			if (v >= 0 && v <= 2) {
				vZone = "小于等于2秒";
			} else if (v > 2 && v <= 5) {
				vZone = "2到5秒";
			} else {
				vZone = "大于5秒";
			}
			// 笔数区间
			String pageSizeZone = null;
			if (pageSize != null) {
				if (pageSize >= 0 && pageSize <= 50) {
					pageSizeZone = "小于等于50笔";
				} else if (pageSize > 50 && pageSize <= 1000) {
					pageSizeZone = "50到1000笔";
				} else if (pageSize > 1000 && pageSize < 10000) {
					pageSizeZone = "1000到10000笔";
				} else {
					pageSizeZone = "大于10000笔";
				}
			}

			// 如果是过滤搜索，判断是否满足过滤条件
			List<String> filterFieldList = Arrays.asList("businessModuleName", "menuId", "menuName", "urlApi", "pageLabelName",
					"pageSizeStr", "speed", "speedZone", "pageSizeZone", "buttonName", "buttonSize", "operatorName");
			List<String> filterValList = Arrays.asList(menuMapping.getBusinessModuleName(), bp.getMenuId(),
					bp.getMenuName(), bp.getUrlApi(), bp.getPageLabelName(), pageSizeStr, String.valueOf(v),
					vZone, pageSizeZone, bp.getButtonName(), bp.getButtonSize(), bp.getOperatorName());

			BusinessPerformanceTransVo vo = null;
			String domainCode = systemDomainInfo.getSystemDomainCode();
			String domainName = systemDomainInfo.getSystemDomainName();
			if ("budget".equals(domainCode)) {
				changeData(budgetDataMap, bp, vo, budgetSeq, domainName, menuMapping, pageSizeStr, v, vZone, pageSizeZone, totalReqCount);
			} else if ("implement".equals(domainCode)) {
				changeData(implementDataMap, bp, vo, implementSeq, domainName, menuMapping, pageSizeStr, v, vZone, pageSizeZone, totalReqCount);

			} else if ("check".equals(domainCode)) {
				changeData(checkDataMap, bp, vo, checkSeq, domainName, menuMapping, pageSizeStr, v, vZone, pageSizeZone, totalReqCount);
			} else if ("fanruan".equals(domainCode)) {
				changeData(fanruanDataMap, bp, vo, fanruanSeq, domainName, menuMapping, pageSizeStr, v, vZone, pageSizeZone, totalReqCount);
			} else {
				// 非预算域、非执行域
				continue;
			}

			// 统计用户数
			operatorIdSet.add(bp.getOperatorId());

			// 组装过滤项数据
			if (filterMap == null) {
				continue;
			}
			for (int j = 0; j < filterFieldList.size(); j++) {
				String filterField = filterFieldList.get(j);
				String filterVal = filterValList.get(j) == null ? "" : filterValList.get(j);
				List<SelectPojo> selectPojoList;
				selectPojoList = filterMap.computeIfAbsent(filterField, k -> new ArrayList<>());
				if (selectPojoList.stream().noneMatch(k -> k.getKey().equals(filterVal))) {
					SelectPojo sp = new SelectPojo();
					sp.setKey(filterVal);
					sp.setValue(filterVal);
					selectPojoList.add(sp);
				}
			}
		}

		// 7、分类返回结果集
		map.put("budget", budgetDataMap);
		map.put("implement", implementDataMap);
		map.put("check", checkDataMap);
		map.put("fanruan", fanruanDataMap);
		map.put("activeOperatorCount", operatorIdSet.size());
		map.put("collectDataCount", totalReqCount);
		return map;
	}

	/**
	 * 过滤数据，设置filterMap
	 */
	public List<BusinessPerformanceTransVo> filterData(BusinessPerformanceParams params, Map<String, List<SelectPojo>> filterMap, List<BusinessPerformanceTransVo> dataList) {
		Iterator<BusinessPerformanceTransVo> iterator = dataList.iterator();
		// 如果是过滤搜索，判断是否满足过滤条件
		List<String> filterFieldList = Arrays.asList("businessModuleName", "menuId", "menuName", "urlApi", "pageLabelName",
				"pageSizeStr", "speed", "speedZone", "pageSizeZone", "buttonName", "buttonSize",
				"operatorName", "buttonUrlApi", "buttonSpeed", "buttonSpeedZone", "buttonReqCount");
		if (filterMap != null) {
			filterMap.clear();
			while (iterator.hasNext()) {
				BusinessPerformanceTransVo bp = iterator.next();

				List<String> filterValList = Arrays.asList(bp.getBusinessModuleName(), bp.getMenuId(),
						bp.getMenuName(), bp.getUrlApi(), bp.getPageLabelName(), bp.getPageSizeStr(), bp.getSpeed(),
						bp.getSpeedZone(), bp.getPageSizeZone(), bp.getButtonName(), bp.getButtonSize(), bp.getOperatorName(),
						bp.getButtonUrlApi(), bp.getButtonSpeed(), bp.getButtonSpeedZone(), bp.getButtonReqCount());
				// 组装过滤项数据
				for (int j = 0; j < filterFieldList.size(); j++) {
					String filterField = filterFieldList.get(j);
					String filterVal = filterValList.get(j) == null ? "" : filterValList.get(j);
					List<SelectPojo> selectPojoList;
					selectPojoList = filterMap.computeIfAbsent(filterField, k -> new ArrayList<>());
					if (selectPojoList.stream().noneMatch(k -> k.getKey().equals(filterVal))) {
						SelectPojo sp = new SelectPojo();
						sp.setKey(filterVal);
						sp.setValue(filterVal);
						selectPojoList.add(sp);
					}
				}

				if (params.getIsFilterSearch() == 1) {
					Map<String, List<String>> busiFilterFormData = params.getBusiFilterFormData();
					for (String key : busiFilterFormData.keySet()) {
						List<String> l = busiFilterFormData.get(key);
						int inx = filterFieldList.indexOf(key);
						if (!CollectionUtils.isEmpty(l) && inx >= 0) {
							String filterVal = filterValList.get(inx);
							if (filterVal == null) {
								filterVal = "";
							}
							if (!l.contains(filterVal)) {
								iterator.remove();
								break;
							}
						}
					}
				}

			}

		}

		return dataList;
	}

	/**
	 * 设置导出样式
	 *
	 * @param wb wb
	 */
	private void createStyle(HSSFWorkbook wb) {
		this.cellStyleMap = new HashMap<>();

		HSSFPalette palette = wb.getCustomPalette();
		palette.setColorAtIndex(IndexedColors.ORANGE.getIndex(), (byte) 237, (byte) 125, (byte) 49);
		palette.setColorAtIndex(IndexedColors.LIGHT_ORANGE.getIndex(), (byte) 255, (byte) 184, (byte) 77);

		CellStyle style1 = wb.createCellStyle();
		// 居中
		style1.setAlignment(HorizontalAlignment.CENTER);
		style1.setVerticalAlignment(VerticalAlignment.CENTER);
		// 边框
		style1.setBorderTop(BorderStyle.THIN);
		style1.setBorderBottom(BorderStyle.THIN);
		style1.setBorderLeft(BorderStyle.THIN);
		style1.setBorderRight(BorderStyle.THIN);
		// 背景色
		style1.setFillPattern(FillPatternType.SOLID_FOREGROUND);
		style1.setFillForegroundColor(palette.getColor(IndexedColors.ORANGE.getIndex()).getIndex());
		// 自动换行
		style1.setWrapText(true);
		Font titleFont1 = wb.createFont();
		// 字体
		titleFont1.setFontName("Arial");
		// 大小
		titleFont1.setFontHeightInPoints((short) 12);
		// 加粗
		titleFont1.setBold(true);
		style1.setFont(titleFont1);
		this.cellStyleMap.put("firstCell", style1);

		CellStyle style2 = wb.createCellStyle();
		style2.setAlignment(HorizontalAlignment.CENTER);
		style2.setVerticalAlignment(VerticalAlignment.CENTER);
		style2.setBorderTop(BorderStyle.THIN);
		style2.setBorderBottom(BorderStyle.THIN);
		style2.setBorderLeft(BorderStyle.THIN);
		style2.setBorderRight(BorderStyle.THIN);
		style2.setFillPattern(FillPatternType.SOLID_FOREGROUND);
		style2.setFillForegroundColor(palette.getColor(IndexedColors.LIGHT_ORANGE.getIndex()).getIndex());
		style2.setWrapText(true);
		Font titleFont2 = wb.createFont();
		titleFont2.setFontName("Arial");
		titleFont2.setFontHeightInPoints((short) 12);
		titleFont2.setBold(true);
		style2.setFont(titleFont2);
		this.cellStyleMap.put("headCell", style2);

		CellStyle style3 = wb.createCellStyle();
		style3.setAlignment(HorizontalAlignment.CENTER);
		style3.setVerticalAlignment(VerticalAlignment.CENTER);
		style3.setBorderTop(BorderStyle.THIN);
		style3.setBorderBottom(BorderStyle.THIN);
		style3.setBorderLeft(BorderStyle.THIN);
		style3.setBorderRight(BorderStyle.THIN);
		style3.setWrapText(true);
		Font titleFont3 = wb.createFont();
		titleFont3.setFontName("Arial");
		titleFont3.setFontHeightInPoints((short) 12);
		style3.setFont(titleFont3);
		this.cellStyleMap.put("contentCell", style3);
	}

	/**
	 * 创建预算域sheet
	 *
	 * @param wb   wb
	 * @param list list
	 */
	private void createBudgetSheet(HSSFWorkbook wb, List<List<String>> list, String sheetName) {
		HSSFSheet sheet = wb.createSheet(sheetName);
		int rowNum = 0;
		// 需要合并的列索引
		List<Integer> mustMergedColumnInxList = Arrays.asList(1, 2, 3, 4, 7, 12, 16, 17, 19);
		// 列宽
		Integer[] columnWidthArr = {8, 11, 15, 19, 19, 34, 34, 34, 15, 15, 15, 15, 15, 6, 16, 18, 34, 34, 20, 20};

		// 第一行
		HSSFRow firstRow = sheet.createRow(rowNum++);
		firstRow.setHeightInPoints(33.38f);

		// 头行
		String[] headColumnNames = {"序号", "域名", "业务模块", "菜单ID", "菜单名称", "前端后台接口", "业务中台接口", "页签", "数量", "速度(秒/笔)",
				"速度区间分布", "笔数区间分布", "按钮", "数量", "速度(秒/笔)", "速度区间分布", "前端后台接口", "业务中台接口", "访问量", "生产环境具体用户"};
		HSSFRow headRow = sheet.createRow(rowNum++);
		headRow.setHeightInPoints(42.38f);
		for (int i = 0; i < headColumnNames.length; i++) {
			sheet.setColumnWidth(i, 256 * columnWidthArr[i] + 184);

			HSSFCell firstCell = firstRow.createCell(i);
			firstCell.setCellStyle(this.cellStyleMap.get("firstCell"));
			firstCell.setCellValue("业务功能");

			HSSFCell headCell = headRow.createCell(i);
			headCell.setCellStyle(this.cellStyleMap.get("headCell"));
			headCell.setCellValue(headColumnNames[i]);
		}

		// 数据行
		int maxRow = Math.min(list.size(), 60000);
		Map<String, List<CellRangeAddress>> cellMergedMap = new HashMap<>();
		for (int i = 0; i < maxRow; i++) {
			HSSFRow dataRow = sheet.createRow(rowNum++);
			dataRow.setHeightInPoints(33.38f);
			List<String> data = list.get(i);
			for (int j = 0; j < data.size(); j++) {
				HSSFCell dataCell = dataRow.createCell(j);
				String value = data.get(j);
				dataCell.setCellStyle(this.cellStyleMap.get("contentCell"));
				dataCell.setCellValue(value);

				// 需要合并的单元格
				if (dataRow.getRowNum() == 2) {
					continue;
				}
				if (mustMergedColumnInxList.contains(j) && value != null && value.equals(list.get(i - 1).get(j))) {
					final int r = dataRow.getRowNum();
					final int c = j;
					List<CellRangeAddress> cellRangeAddressList = cellMergedMap
							.computeIfAbsent(value + "_" + j, k -> new ArrayList<>());
					if (CollectionUtils.isEmpty(cellRangeAddressList)) {
						cellRangeAddressList.add(new CellRangeAddress(r - 1, r, c, c));
						continue;
					}
					CellRangeAddress cellRangeAddress = cellRangeAddressList.get(cellRangeAddressList.size() - 1);
					if (cellRangeAddress.getLastRow() == r - 1) {
						cellRangeAddress.setLastRow(r);
					} else {
						cellRangeAddressList.add(new CellRangeAddress(r - 1, r, c, c));
					}
				}
			}
		}

		// 合并单元格
		sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, headColumnNames.length - 1));
		cellMergedMap.forEach((k, vs) -> {
			vs.forEach(sheet::addMergedRegion);
		});
	}

	/**
	 * 创建执行域sheet
	 *
	 * @param wb   wb
	 * @param list list
	 */
	private void createImplementSheet(HSSFWorkbook wb, List<List<String>> list) {
		HSSFSheet sheet = wb.createSheet("执行域页面功能");
		int rowNum = 0;
		// 需要合并的列索引
		List<Integer> mustMergedColumnInxList = Arrays.asList(new Integer[]{1, 2, 3, 4, 5, 8, 13, 17, 18, 20});
		// 列宽
		Integer[] columnWidthArr = {8, 11, 15, 19, 19, 19, 34, 34, 34, 15, 15, 15, 15, 15, 6, 16, 18, 34, 34, 20, 20};

		// 第一行
		HSSFRow firstRow = sheet.createRow(rowNum++);
		firstRow.setHeightInPoints(33.38f);

		// 头行
		String[] headColumnNames = {"序号", "域名", "业务模块", "菜单ID", "一级菜单", "二级菜单", "前端后台接口", "业务中台接口", "页签", "数量", "速度(秒/笔)",
				"速度区间分布", "笔数区间分布", "按钮", "数量", "速度(秒/笔)", "速度区间分布", "前端后台接口", "业务中台接口", "访问量", "生产环境具体用户"};
		HSSFRow headRow = sheet.createRow(rowNum++);
		headRow.setHeightInPoints(42.38f);
		for (int i = 0; i < headColumnNames.length; i++) {
			sheet.setColumnWidth(i, 256 * columnWidthArr[i] + 184);

			HSSFCell firstCell = firstRow.createCell(i);
			firstCell.setCellStyle(this.cellStyleMap.get("firstCell"));
			firstCell.setCellValue("业务功能");

			HSSFCell headCell = headRow.createCell(i);
			headCell.setCellStyle(this.cellStyleMap.get("headCell"));
			headCell.setCellValue(headColumnNames[i]);
		}

		// 数据行
		int maxRow = Math.min(list.size(), 60000);
		Map<String, List<CellRangeAddress>> cellMergedMap = new HashMap<>();
		for (int i = 0; i < maxRow; i++) {
			HSSFRow dataRow = sheet.createRow(rowNum++);
			dataRow.setHeightInPoints(33.38f);
			List<String> data = list.get(i);
			for (int j = 0; j < data.size(); j++) {
				HSSFCell dataCell = dataRow.createCell(j);
				String value = data.get(j);
				dataCell.setCellStyle(this.cellStyleMap.get("contentCell"));
				dataCell.setCellValue(value);

				// 需要合并的单元格
				if (dataRow.getRowNum() == 2) {
					continue;
				}
				if (mustMergedColumnInxList.contains(j) && value != null && value.equals(list.get(i - 1).get(j))) {
					final int r = dataRow.getRowNum();
					final int c = j;
					List<CellRangeAddress> cellRangeAddressList = cellMergedMap
							.computeIfAbsent(value + "_" + j, k -> new ArrayList<>());
					if (CollectionUtils.isEmpty(cellRangeAddressList)) {
						cellRangeAddressList.add(new CellRangeAddress(r - 1, r, c, c));
						continue;
					}
					CellRangeAddress cellRangeAddress = cellRangeAddressList.get(cellRangeAddressList.size() - 1);
					if (cellRangeAddress.getLastRow() == r - 1) {
						cellRangeAddress.setLastRow(r);
					} else {
						cellRangeAddressList.add(new CellRangeAddress(r - 1, r, c, c));
					}
				}
			}
		}

		// 合并单元格
		sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, headColumnNames.length - 1));
		cellMergedMap.forEach((k, vs) -> {
			vs.forEach(sheet::addMergedRegion);
		});
	}


	/**
	 * 查询用户操作行为列表
	 *
	 * @param params 业务性能指标查询参数对象
	 * @return 统一返回对象
	 */
	@Override
	public R queryOperatorBehaviorList(BusinessPerformanceParams params) {
		// 0、加载映射配置
		List<ConfPageLabelMapping> data = pageLabelMappingService.getAllPageLabelMapping().getData();
		List<PageLabelMapping> pageLabelMappingList = BeanUtil.copyToList(data, PageLabelMapping.class);
		pageLabelMappingMap = pageLabelMappingList
				.stream().collect(Collectors.toMap(PageLabelMapping::getPageLabelId, t -> t, (k1, k2) -> k1));
		List<ConfPageLabelMapping> confPageLabelMappings = buttonMappingService.getAllConfButtonMapping().getData();
		List<ButtonMapping> buttonMappingList = BeanUtil.copyToList(confPageLabelMappings, ButtonMapping.class);
		buttonMappingMap = buttonMappingList
				.stream().collect(Collectors.toMap(ButtonMapping::getButtonId, t -> t, (k1, k2) -> k1));

		List<OperatorBehaviorVo> obVoList = new ArrayList<>();
		// 1、查询用户在某系统采集到的操作笔数
		params.setTableName(TableNameEnum.BUSINESS_STEP.getName());
		Long operatorTotalCount = businessPerformanceMapper.queryUserOperationCount(params);
		// 2、分页查询，返回结果
		Page<OperatorBehaviorVo> page = new Page<>(params.getPageNum(), params.getPageSize());
		List<OperatorBehaviorVo> list = businessPerformanceMapper.queryOperatorBehaviorList(page, params);

		// 3、处理结果
		for (OperatorBehaviorVo obVo : list) {

			// 枚举值转换
			BusiPerforMenuMapping m1 = menuMappingMap.get(obVo.getMenuId());
			obVo.setMenuName(m1 == null ? null : m1.getMenuName());

			PageLabelMapping m2 = pageLabelMappingMap.get(obVo.getPageLabelId());
			obVo.setPageLabelName(m2 == null ? null : m2.getPageLabelName());

			ButtonMapping m4 = buttonMappingMap.get(obVo.getButtonId());
			obVo.setButtonName(m4 == null ? null : m4.getButtonName());

			obVo.setReqCount("1");
			obVoList.add(obVo);
		}
		Map<String, Object> res = new HashMap<>();
		res.put("pageDataInfo", new PageDataInfo(page));
		res.put("operatorTotalCount", operatorTotalCount);


		return R.ok(res);
	}

	/**
	 * 查询业务功能图表信息
	 *
	 * @param params 业务性能指标查询参数对象
	 * @return 统一返回对象
	 */
	@Override
	public R queryBusinessFunctionChartData(BusinessPerformanceParams params) {
		List<BusiLineChatrDataVo> obVoList = new ArrayList<>();

//        String[] fields = {"urlApi", "dealTime", "requestBytes", "responseBytes", "endTime"};
		params.setTableName(TableNameEnum.BUSINESS_STEP.getName());
		obVoList = businessPerformanceMapper.queryBusinessFunctionChartData(params);

		Comparator<BusiLineChatrDataVo> comparator = null;
		comparator = Comparator.comparing(BusiLineChatrDataVo::getEndTime);
		List<BusiLineChatrDataVo> resList = new ArrayList<>();
		BusiLineChatrResVo result = new BusiLineChatrResVo();
		// 如果查询参数 操作员ID 为空则需要对结果数据相同的 endTime 数据进行聚合
		if (StringUtils.isEmpty(params.getOperatorId()) && !obVoList.isEmpty()) {
			List<BusiLineChatrDataVo> finalResList = new ArrayList<>();
			obVoList.stream().collect(Collectors.groupingBy(BusiLineChatrDataVo::getEndTime))
					.forEach((endTime, sameTimeList) -> {

						BusiLineChatrDataVo vo = new BusiLineChatrDataVo();
						vo.setEndTime(endTime);
						vo.setUrlApi(params.getUrlApi());
						vo.setDealTime(sameTimeList.stream().mapToLong(BusiLineChatrDataVo::getDealTime).sum());
						vo.setRequestBytes(sameTimeList.stream().mapToLong(BusiLineChatrDataVo::getRequestBytes).sum());
						vo.setResponseBytes(sameTimeList.stream().mapToLong(BusiLineChatrDataVo::getResponseBytes).sum());

						finalResList.add(vo);
					});

			resList = finalResList.stream().sorted(comparator).collect(Collectors.toList());

			// 封装数据
			performDataEncapsulation(resList, params, result);

			return R.ok(result);
		}

		// 封装数据
		performDataEncapsulation(obVoList, params, result);

		return R.ok(result);
	}

	/**
	 * 封装数据
	 *
	 * @param resList 待封装数据集
	 * @param params  参数对象
	 * @param result  结果集
	 */
	private void performDataEncapsulation(List<BusiLineChatrDataVo> resList,
										  BusinessPerformanceParams params,
										  BusiLineChatrResVo result) {
		if (Objects.isNull(result)) {
			result = new BusiLineChatrResVo();
		}
		// 回填URL
		if (StringUtils.isEmpty(params.getButtonName())
				|| "null".equalsIgnoreCase(params.getButtonName())) {
			result.setUrlApi(params.getUrlApi());
		} else {
			result.setUrlApi(params.getButtonId());
		}
		// 请求总笔数
		result.setReqCount(resList.size());
		result.setOperatorName(params.getOperatorName());

		// 获取配置库里的 平均办理时长的倍数, 并计算与 平均处理时长的乘积
		int multipleOfAvgDealTime = 2;
		String multipleOfAvgDealTimeStr = ParamResolver.getStr(ConfigKey.MULTIPLE_AVGDEAL_TIME).trim();
		if (StringUtils.isNotEmpty(multipleOfAvgDealTimeStr) && StringUtils.isNumeric(multipleOfAvgDealTimeStr)) {
			multipleOfAvgDealTime = Integer.parseInt(multipleOfAvgDealTimeStr);
		}
		long avgDealTimeProduct = getDealTimeProdect(resList, multipleOfAvgDealTime, result);

		// 遍历数据集获取超过 （平均处理时长 * multipleOfAvgDealTime） 的数据笔数
		int exceedAvgDealTimeReqCount = 0;
		for (BusiLineChatrDataVo vo : resList) {
			if (vo.getDealTime() > avgDealTimeProduct) {
				exceedAvgDealTimeReqCount++;
				vo.setIsExceedAvgDealTime(1);
			}
		}
		result.setExceedAvgDealTimeReqCount(exceedAvgDealTimeReqCount);

		// 是否存在超过（平均处理时长 * multipleOfAvgDealTime） 的数据点 0-否  1-是
		if (exceedAvgDealTimeReqCount > 0) {
			result.setIsExceedAvgDealTime(1);
		}

		result.setLineList(resList);

	}

	/**
	 * 计算平均处理时长 与 指定倍数的乘积
	 *
	 * @param resList
	 * @param multipleOfAvgDealTime
	 * @return
	 */
	private long getDealTimeProdect(List<BusiLineChatrDataVo> resList,
									int multipleOfAvgDealTime,
									BusiLineChatrResVo result) {
		Long avgDealTime = resList.stream().collect(Collectors.summingLong(BusiLineChatrDataVo::getDealTime)) / (resList.size() == 0 ? 1 : resList.size());
		Long avgDealTimeProduct = avgDealTime * multipleOfAvgDealTime;
		result.setAvgDealTime(avgDealTime);
		result.setMultipleOfAvgDealTime(multipleOfAvgDealTime);

		return avgDealTimeProduct;
	}


	private List<BusinessPerformanceVo> queryPerformanceList(BusinessPerformanceParams params) {

		// 3、设置表信息集，默认排序
		params.setTableName(TableNameEnum.BUSINESS_URL_API_STAT.getName());
		Page<BusinessPerformanceVo> page = null;

		return businessPerformanceMapper.queryBusinessPerformanceList(page, params);
		//1、计算表名
		//2、去除不存在的表名
		//3、查询数据
	}

	private List<BusinessPerformanceVo> queryPerformanceList2(BusinessPerformanceParams params) {

		params.setTableName(TableNameEnum.BUSINESS_URL_API_STAT.getName());
		Page<BusinessPerformanceVo> page = null;

		return businessPerformanceMapper.queryBusinessPerformanceList2(page, params);
	}
}
